﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NFit.Core
{
    /// <summary>
    /// Default implementation for <see cref="INameProvider"/>
    /// </summary>
    public class DefaultNameProvider : INameProvider
    {
        /// <summary>
        /// Transform a string by making it compliant to a code name. For example, removing accents or spaces
        /// </summary>
        /// <param name="input">the input string</param>
        /// <returns>conformed string</returns>
        public string ConformString(string input)
        {
            string res = input;
            res = res.Replace("ç", "c");
            res = res.Replace("à", "a");
            res = res.Replace("ä", "a");
            res = res.Replace("â", "a");
            res = res.Replace("é", "e");
            res = res.Replace("è", "e");
            res = res.Replace("ê", "e");
            res = res.Replace("ë", "e");
            res = res.Replace("ï", "i");
            res = res.Replace("î", "i");
            res = res.Replace("ö", "o");
            res = res.Replace("ô", "o");
            res = res.Replace("ù", "u");
            res = res.Replace("ü", "u");
            res = res.Replace("û", "u");
            res = res.Replace("%", "Percent");
            res = res.Replace("$", "Dollars");
            res = res.Replace("€", "Euros");
            res = res.Replace("£", "Pounds");
            res = RemoveMethodIdentifier(res);
            return res;
        }

        /// <summary>
        /// Build an element name by concatenation of the strings and appliance of PascalCase
        /// </summary>
        /// <param name="inputs">the list of strings input</param>
        /// <returns></returns>
        public string ElementName(params string[] inputs)
        {
            System.Text.StringBuilder sb = new StringBuilder();
            foreach(string s in inputs)
            {
                string conformed = ConformString(s);
                if (conformed.Contains(" "))
                {
                    string[] splitted = conformed.Split(' ');
                    conformed = ElementName(splitted);
                }
                if (!string.IsNullOrEmpty(conformed))
                {                    
                    sb.Append(conformed[0].ToString().ToUpper());
                    sb.Append(conformed.Substring(1));
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Indicate if the input string is a method. For example fit's method name end with "()" or "?"
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public bool IsAMethod(string input)
        {
            if (input.Trim().EndsWith("?"))
                return true;

            if (input.Trim().EndsWith("()"))
                return true;

            return false;
        }

        /// <summary>
        /// Remove the method identifier of the input. ConformString may call this method...
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public string RemoveMethodIdentifier(string input)
        {
            input = input.Replace("?", "");
            input = input.Replace("()", "");
            return input;
        }

        /// <summary>
        /// Indicate if the input could be considered as a keyword of the provided type. 
        /// This method help translating keywords or at least flexibility about the keywords in fixtures like ActionFixture
        /// </summary>
        /// <param name="keyword">the keyword "type" or root definition</param>
        /// <param name="input">the input string</param>
        /// <returns>true if the input match the keyword</returns>
        public bool IsAKeywordFor(string keyword, string input)
        {
            if (keyword == input)
                return true;

            ////TODO implement a keyword mecanism instead...

            return false;
        }
    }
}
